using System;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Text;

namespace Waymex.Xml
{
    /// <summary>
    /// Tis class is used to transform Xml documents using Xslt documents.
    /// </summary>
    public class Transform
    {
        /// <summary>
        /// Enumetrator indicating the return type (i.e. Text or XML)
        /// </summary>
        public enum OutputType
        {
            /// <summary>
            /// Returns the transformed data as an unformatted string.
            /// </summary>
            Text,
            /// <summary>
            /// Returns the transformed data as a string but with an Xml declaraions and insdentation. 
            /// </summary>
            Xml,
        }
        /// <summary>
        /// Transformns the specified Xml string using the specified Xslt document.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="xslFileName"></param>
        /// <returns></returns>
        public static string XsltTransform(String xml, String xslFileName)
        {
            return (XsltTransform(xml, xslFileName, null, OutputType.Text));
        }
        /// <summary>
        /// Transformns the specified Xml string using the specified Xslt document.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="xsltDocument"></param>
        /// <returns></returns>
        public static string XsltTransform(String xml, Stream xsltDocument)
        {
            return (XsltTransform(xml, xsltDocument, null, OutputType.Text));
        }
        /// <summary>
        /// Transformns the specified Xml string using the specified Xslt document.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="xslFileName"></param>
        /// <param name="output"></param>
        /// <returns></returns>
        public static string XsltTransform(String xml, String xslFileName, OutputType output)
        {
            return (XsltTransform(xml, xslFileName, null, output));
        }
        /// <summary>
        /// Transformns the specified Xml string using the specified Xslt document.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="xsltDocument"></param>
        /// <param name="output"></param>
        /// <returns></returns>
        public static string XsltTransform(String xml, Stream xsltDocument, OutputType output)
        {
            return (XsltTransform(xml, xsltDocument, null, output));
        }
        /// <summary>
        /// Transformns the specified Xml string using the specified Xslt document.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="xslFileName"></param>
        /// <param name="xsltArguments"></param>
        /// <param name="output"></param>
        /// <returns></returns>
        public static string XsltTransform(String xml, String xslFileName, XsltArgumentList xsltArguments, OutputType output)
        {
            //create transform object from xslt file
            XslCompiledTransform xsltTransform = new XslCompiledTransform();
            xsltTransform.Load(xslFileName);
            return XsltTransform(xml, xsltTransform, xsltArguments, output);
        }
        /// <summary>
        /// Transformns the specified Xml string using the specified Xslt document.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="xsltDocument"></param>
        /// <param name="xsltArguments"></param>
        /// <param name="output"></param>
        /// <returns></returns>
        public static string XsltTransform(String xml, Stream xsltDocument, XsltArgumentList xsltArguments, OutputType output)
        {

            ////convert the stream to a string for debug purposes
            byte[] buffer = new byte[xsltDocument.Length];
            xsltDocument.Read(buffer, 0, (int)xsltDocument.Length);
            string dataOut = Encoding.UTF8.GetString(buffer).Trim();

            XmlDocument xmlreader = new XmlDocument();
            xmlreader.LoadXml(dataOut);

            //            XmlReader xmlreader = XmlReader.Create(xsltDocument);

            //create transform object from xslt file
            XslCompiledTransform xsltTransform = new XslCompiledTransform();
            xsltTransform.Load(xmlreader);

            return XsltTransform(xml, xsltTransform, xsltArguments, output);
        }
        /// <summary>
        /// Transformns the specified Xml string using the specified Xslt document.
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="xsltTransform"></param>
        /// <param name="xsltArguments"></param>
        /// <param name="output"></param>
        /// <returns></returns>
        private static string XsltTransform(String xml, XslCompiledTransform xsltTransform, XsltArgumentList xsltArguments, OutputType output)
        {

            StringBuilder sbXml = new StringBuilder();
            String dataOut = String.Empty;

            //create XPath document from xml string
            XPathDocument xpathDocument = new XPathDocument(new StringReader(xml));

            //use a memory stream as this allows us to use a XmlWriter rather than a string writer
            MemoryStream mstream = new MemoryStream();
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();

            switch (output)
            {

                case OutputType.Text:

                    xmlWriterSettings.OmitXmlDeclaration = true;
                    xmlWriterSettings.Indent = false;
                    xmlWriterSettings.Encoding = Encoding.Unicode;

                    break;

                case OutputType.Xml:

                    xmlWriterSettings.OmitXmlDeclaration = false;
                    xmlWriterSettings.Indent = true;
                    xmlWriterSettings.Encoding = Encoding.UTF8;

                    break;

            }

            //create an XmlWriter passing in the stream to be populated and the encoding
            XmlWriter xmlWriter = XmlWriter.Create(mstream, xmlWriterSettings);

            //add a declaration if required
            xmlWriter.WriteStartDocument();

            //transform the xml
            xsltTransform.Transform(xpathDocument, xsltArguments, xmlWriter);

            //convert the stream back to a string
            dataOut = Encoding.UTF8.GetString(mstream.ToArray());


            return dataOut;

        }

    }
}